package com.carter.springframework.core.annotation;

import java.lang.annotation.Annotation;

public abstract class MergedAnnotationSelectors {
    private static final MergedAnnotationSelector<?> NEAREST = new Nearest();

    private static final MergedAnnotationSelector<?> FIRST_DIRECTLY_DECLARED = new FirstDirectlyDeclared();

    private MergedAnnotationSelectors() {
    }

    public static <A extends Annotation> MergedAnnotationSelector<A> nearest() {
        return (MergedAnnotationSelector<A>) NEAREST;
    }

    /**
     * Select the first directly declared annotation when possible. If no direct
     * annotations are declared then the nearest annotation is selected.
     * @return a selector that picks the first directly declared annotation whenever possible
     */
    @SuppressWarnings("unchecked")
    public static <A extends Annotation> MergedAnnotationSelector<A> firstDirectlyDeclared() {
        return (MergedAnnotationSelector<A>) FIRST_DIRECTLY_DECLARED;
    }

    private static class Nearest implements MergedAnnotationSelector<Annotation> {
        //聚合索引不为0，则挑一个聚合索引比较小的，也就是先被扫描的
        @Override
        public MergedAnnotation<Annotation> select(MergedAnnotation<Annotation> existing, MergedAnnotation<Annotation> candidate) {
            if (candidate.getDistance() < existing.getDistance()) {
                return candidate;
            }
            return existing;
        }

        /**
         * 聚合索引为0，说明注解直接出现在被扫描的AnnotatedElement上，是最符合的
         * @param annotation
         * @return
         */
        @Override
        public boolean isBestCandidate(MergedAnnotation<Annotation> annotation) {
            return annotation.getDistance()==0;
        }
    }

    private static class FirstDirectlyDeclared implements MergedAnnotationSelector<Annotation> {
        //聚合索引为0，说明注解直接出现在被扫描的AnnotatedElement上，是最符合的
        @Override
        public boolean isBestCandidate(MergedAnnotation<Annotation> annotation) {
            return annotation.getDistance() == 0;
        }

        //仅当已有注解没有直接出现在被扫描的AnnotatedElement上，但是新注解直接出现在了扫描的AnnotatedElement上的时候，才返回新注解
        @Override
        public MergedAnnotation<Annotation> select(
                MergedAnnotation<Annotation> existing, MergedAnnotation<Annotation> candidate) {

            if (existing.getDistance() > 0 && candidate.getDistance() == 0) {
                return candidate;
            }
            return existing;
        }

    }
}
